package com.xiaomo.core;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;

import com.xiaomo.model.MultiUnit;
import com.xiaomo.model.Schedule;
import com.xiaomo.model.SingleUnit;
import com.xiaomo.model.Task;
import com.xiaomo.model.Unit;
import com.xiaomo.utils.LogUtil;

public class TaskBuilder {
	private final static  LogUtil log = new LogUtil(TaskBuilder.class);
	private static Task task = new Task();
	
	/**
	 * 解析XML，生成Task和Unit
	 * @param fileName 文件名
	 */
	public static void getTaskFromXML(String fileName){
		getTaskFromXML(new File (fileName));
	}
	
	/**
	 * 从数据库中读取的字符串，转换成Task
	 * @param strTask
	 */
	public static void getTaskFromDBString(String strTask){
		InputStream is = new ByteArrayInputStream(strTask.getBytes());
		getTaskFromXML(is);
	}
	
	public  static void getTaskFromXML(File file) {
		try {
			InputStream is = new FileInputStream(file);
			getTaskFromXML(is);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
	}

	public static Task getTaskFromXML(InputStream resourceAsStream) {
		try {
			Document doc = new SAXBuilder().build(resourceAsStream);
			getTaskFromXML(doc);
		} catch (JDOMException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return task;
	}
	
	/**
	 * 解析XML，生成Task和Unit
	 * @param fileName 文件名
	 */
	public static Task getTaskFromXML(Document doc){
			Element xTask = doc.getRootElement();
			Element xUnits = xTask.getChild(TaskEnum.units.toString());
			Element xSchedules = xTask.getChild(TaskEnum.schedules.toString());
			task.setUnits( getUnits(xUnits));
			task.setSchedules(getSchedules(xSchedules));
			phraseMultiUnit2SingleUnit();
			return task;
	}

	private static  List<Schedule> getSchedules(Element xSchedules) {
		Iterator xScheduleIter = xSchedules.getChildren(TaskEnum.schedule.toString()).iterator();
		List<Schedule> listSchedules = new ArrayList<Schedule>();
		Schedule schedule = null;
		Unit unit = null;
		String unitName = null;
		Map<String,Unit> mapUnits = task.getUnits();
		while (xScheduleIter.hasNext()) {
			Element xSchedule = (Element) xScheduleIter.next();
			schedule = new Schedule();
			unitName = xSchedule.getAttributeValue("thisUnit");
			if (mapUnits.containsKey(unitName)) {
				unit = mapUnits.get(unitName );
				schedule.setThisUnit(unit);
			}else {
				log.error(String.format("不存在名字为%s的thisUnit", unitName));
				System.exit(0);
			}
			listSchedules.add(schedule);
		}
		return listSchedules;
	}
	
	private static SingleUnit getSingleUnit(Element xUnit){
		SingleUnit singleUnit = new SingleUnit();
		try{
			singleUnit.setName(xUnit.getAttributeValue("name"));
			singleUnit.setDescribe(xUnit.getAttributeValue("describe"));
			singleUnit.setType(xUnit.getAttributeValue("type"));
			Class<?> c = (Class<ExecuteClass>)Class.forName(xUnit.getAttributeValue("executeClass"));
			singleUnit.setExecuteClass((ExecuteClass) c.newInstance());
			singleUnit.setExecuteClassName(xUnit.getAttributeValue("executeClass"));
			Element xProps = xUnit.getChild((TaskEnum.properties.toString()));
			if (xProps != null) {
				Iterator xPropIter = xProps.getChildren(TaskEnum.property.toString()).iterator();
				Map<String,Object> properties = new HashMap<String,Object>();
				while (xPropIter.hasNext()) {
					Element xProp = (Element) xPropIter.next();
					properties.put(xProp.getAttributeValue("name"), xProp.getAttributeValue("value"));
				}
				singleUnit.setProperties(properties);
				singleUnit.getExecuteClass().setProperties(properties);
			}
			log.info(singleUnit);
		}catch(ClassNotFoundException e){
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		return singleUnit;
	}
	
	private static Map<String,Unit> getUnits(Element xUnits){
		Iterator xUnitIter = xUnits.getChildren(TaskEnum.unit.toString()).iterator();
		Map<String,Unit> mapUnits = new HashMap<String, Unit>();
		String unitType = null;
		while (xUnitIter.hasNext()) {
			Element xUnit =  (Element) xUnitIter.next();
			unitType = xUnit.getAttributeValue("type");
			if (TaskEnum.single.toString().equals(unitType)) {
				mapUnits.put(xUnit.getAttributeValue("name"),getSingleUnit(xUnit));
			}else if (TaskEnum.multi.toString().equals(unitType)) {
				mapUnits.put(xUnit.getAttributeValue("name"),getMultiUnit(xUnit));
			}
		}
		return mapUnits;
	}
	
	private static MultiUnit getMultiUnit(Element xUnit) {
		SingleUnit unit = null;
		MultiUnit multiUnit = new MultiUnit();
		multiUnit.setName(xUnit.getAttributeValue("name"));
		multiUnit.setDescribe(xUnit.getAttributeValue("describe"));
		multiUnit.setType(xUnit.getAttributeValue("type"));
		Element xProps = xUnit.getChild((TaskEnum.subunits.toString()));
		if (xProps != null) {
			Iterator xPropIter = xProps.getChildren(TaskEnum.subunit.toString()).iterator();
			List<SingleUnit> subunits = new ArrayList<SingleUnit>();
			while (xPropIter.hasNext()) {
				Element xProp = (Element) xPropIter.next();
				unit = new SingleUnit();
				unit.setName(xProp.getAttributeValue("ref"));
				subunits.add(unit);
			}
			multiUnit.setSubunits(subunits);
		}
		log.info(multiUnit);
		return multiUnit;
	}
	
	//将Units中的multiUnit中的Units全部解析出来
	private static void phraseMultiUnit2SingleUnit(){
		Map<String, Unit> mapUnits =  task.getUnits();
		MultiUnit multiUnit= null;
		SingleUnit singleUnit= null;
		//将MultiUnit中的ListSubUnits由只有Unit.Name增加为整个Unit
		List<SingleUnit> listSingleUnits = new ArrayList<SingleUnit>();
		for(Entry<String, Unit> entryMultiUnit : mapUnits.entrySet()){
			if (TaskEnum.multi.toString().equals(entryMultiUnit.getValue().getType())){
				multiUnit = (MultiUnit) entryMultiUnit.getValue();
				for (SingleUnit singleUnitOfList : multiUnit.getSubunits()) {
					listSingleUnits.add((SingleUnit) mapUnits.get(singleUnitOfList.getName()));
				}
				multiUnit.setSubunits(listSingleUnits);
			}
		}
		task.setUnits(mapUnits);	
	}
	
}
